﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Reflection;
using System.Text;

namespace Circus.Utility {

    /// <summary>
    /// 提供操作数据库的工具函数。
    /// </summary>
    public static class DbHelper {

        #region 底层连接

        /// <summary>
        /// 获取或设置当前使用的连接字符串。
        /// </summary>
        public static string connectionString = getDefaultConnectionString();

        private static string getDefaultConnectionString() {
            var cs = System.Configuration.ConfigurationManager.ConnectionStrings;
            if (cs["Default"] != null) {
                return cs["Default"].ConnectionString;
            }
            return cs.Count > 0 ? cs[0].ConnectionString : null;
        }

        /// <summary>
        /// 创建一个用于执行命令的连接。
        /// </summary>
        /// <returns>一个连接对象。</returns>
        public static SqlConnection createConnection() {
            var conn = new SqlConnection(connectionString);
            conn.Open();
            return conn;
        }

        /// <summary>
        /// 创建一个存储过程命令。
        /// </summary>
        /// <param name="conn">当前连接对象。</param>
        /// <param name="procedure">要执行的存储过程。</param>
        /// <returns>返回命令对象。</returns>
        public static SqlCommand createProcedure(this SqlConnection conn, string procedure) {
            var cmd = new SqlCommand(procedure, conn);
            cmd.CommandType = CommandType.StoredProcedure;
            return cmd;
        }

        /// <summary>
        /// 创建一个存储过程命令。
        /// </summary>
        /// <param name="conn">当前连接对象。</param>
        /// <param name="procedure">要执行的存储过程。</param>
        /// <param name="args">存储过程使用的参数值。</param>
        /// <returns>返回命令对象。</returns>
        public static SqlCommand createProcedure(this SqlConnection conn, string procedure, params SqlParameter[] args) {
            var cmd = new SqlCommand(procedure, conn);
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.AddRange(args);
            return cmd;
        }

        /// <summary>
        /// 创建一个接收返回值的参数。
        /// </summary>
        /// <param name="dbType">数据库的类型。</param>
        /// <returns>返回参数对象。</returns>
        public static SqlParameter createReturnParameter(SqlDbType dbType = SqlDbType.Int) {
            var result = new SqlParameter("@ReturnValue", dbType);
            result.Direction = ParameterDirection.ReturnValue;
            return result;
        }

        /// <summary>
        /// 创建一个接收返回值的参数。
        /// </summary>
        /// <param name="name">数据库参数名。</param>
        /// <param name="dbType">数据库的类型。</param>
        /// <returns>返回参数对象。</returns>
        public static SqlParameter createOutputParameter(string name, SqlDbType dbType) {
            var result = new SqlParameter(name, dbType);
            result.Direction = ParameterDirection.Output;
            return result;
        }

        /// <summary>
        /// 创建一个接收返回值的参数。
        /// </summary>
        /// <param name="name">数据库参数名。</param>
        /// <param name="dbType">数据库的类型。</param>
        /// <param name="size">数据库字段大小。</param>
        /// <returns>返回参数对象。</returns>
        public static SqlParameter createOutputParameter(string name, SqlDbType dbType, int size) {
            var result = new SqlParameter(name, dbType, size);
            result.Direction = ParameterDirection.Output;
            return result;
        }

        /// <summary>
        /// 添加一个返回类型的参数。
        /// </summary>
        /// <param name="parameters">要添加的参数集合。</param>
        /// <param name="dbType">数据库的类型。</param>
        /// <returns>返回参数对象。</returns>
        public static SqlParameter addReturnParameter(this SqlParameterCollection parameters, SqlDbType dbType = SqlDbType.Int) {
            var result = createReturnParameter(dbType);
            parameters.Add(result);
            return result;
        }

        /// <summary>
        /// 添加一个输出类型的参数。
        /// </summary>
        /// <param name="parameters">要添加的参数集合。</param>
        /// <param name="name">数据库参数名。</param>
        /// <param name="dbType">数据库的类型。</param>
        /// <returns>返回参数对象。</returns>
        public static SqlParameter addOutputParameter(this SqlParameterCollection parameters, string name, SqlDbType dbType) {
            var result = createOutputParameter(name, dbType);
            parameters.Add(result);
            return result;
        }

        /// <summary>
        /// 添加一个输出类型的参数。
        /// </summary>
        /// <param name="parameters">要添加的参数集合。</param>
        /// <param name="name">数据库参数名。</param>
        /// <param name="dbType">数据库的类型。</param>
        /// <param name="size">数据库字段大小。</param>
        /// <returns>返回参数对象。</returns>
        public static SqlParameter addOutputParameter(this SqlParameterCollection parameters, string name, SqlDbType dbType, int size) {
            var result = createOutputParameter(name, dbType, size);
            parameters.Add(result);
            return result;
        }

        /// <summary>
        /// 执行一个命令并返回数据库的返回值。
        /// </summary>
        /// <param name="cmd">要执行的对象。</param>
        /// <param name="dbType">数据库的类型。</param>
        /// <returns>返回数据库返回的对象。</returns>
        public static object executeReturnValue(this SqlCommand cmd, SqlDbType dbType = SqlDbType.Int) {
            var retParam = cmd.Parameters.addReturnParameter(dbType);
            cmd.ExecuteNonQuery();
            return retParam.Value;
        }

        #endregion

        #region 底层执行 SQL 操作

        /// <summary>
        /// 执行 SQL 语句并返回受影响的行数。
        /// </summary>
        /// <param name="sql">要执行的 SQL 语句。</param>
        /// <param name="args">SQL 语句中使用的参数值，对应 SQL 语句中 @0 格式的参数。</param>
        /// <returns>受影响的行数。</returns>
        public static int executeSqlNonQuery(string sql, params object[] args) {
            using (var conn = createConnection()) {
                var cmd = new SqlCommand(sql, conn);
                addParameters(cmd, args);
                return cmd.ExecuteNonQuery();
            }
        }

        /// <summary>
        /// 执行 SQL 语句并返回受影响的行数。
        /// </summary>
        /// <param name="sql">要执行的 SQL 语句。</param>
        /// <returns>受影响的行数。</returns>
        public static int executeSqlNonQuery(string sql) {
            return executeSqlNonQuery(sql, null);
        }

        /// <summary>
        /// 执行 SQL 语句并返回结果集中的第一行的第一列。忽略其它行或列。
        /// </summary>
        /// <param name="sql">要执行的 SQL 语句。</param>
        /// <param name="args">SQL 语句中使用的参数值，对应 SQL 语句中 @0 格式的参数。</param>
        /// <returns>结果集中第一行的第一列；如果结果集为空，则为 null。返回的最大字符数为 2033 个字符。</returns>
        public static object executeSqlScalar(string sql, params object[] args) {
            using (var conn = createConnection()) {
                var cmd = new SqlCommand(sql, conn);
                addParameters(cmd, args);
                return cmd.ExecuteScalar();
            }
        }

        /// <summary>
        /// 执行 SQL 语句并返回结果集中的第一行的第一列。忽略其它行或列。
        /// </summary>
        /// <param name="sql">要执行的 SQL 语句。</param>
        /// <returns>结果集中第一行的第一列；如果结果集为空，则为 null。返回的最大字符数为 2033 个字符。</returns>
        public static object executeSqlScalar(string sql) {
            return executeSqlScalar(sql, null);
        }

        /// <summary>
        /// 执行 SQL 语句并返回一个数据读取器。
        /// </summary>
        /// <param name="sql">要执行的 SQL 语句。</param>
        /// <param name="args">SQL 语句中使用的参数值，对应 SQL 语句中 @0 格式的参数。</param>
        /// <returns>一个数据读取器。需要释放其资源以关闭连接。</returns>
        public static SqlDataReader executeSqlReader(string sql, params object[] args) {
            var conn = createConnection();
            var cmd = new SqlCommand(sql, conn);
            addParameters(cmd, args);
            return cmd.ExecuteReader(CommandBehavior.CloseConnection);
        }

        /// <summary>
        /// 执行 SQL 语句并返回一个数据读取器。
        /// </summary>
        /// <param name="sql">要执行的 SQL 语句。</param>
        /// <returns>一个数据读取器。需要释放其资源以关闭连接。</returns>
        public static SqlDataReader executeSqlReader(string sql) {
            return executeSqlReader(sql, null);
        }

        /// <summary>
        /// 执行数据库语句返回一个用于遍历所有行数据的迭代器。
        /// </summary>
        /// <param name="sql">要执行的 SQL 语句。</param>
        /// <param name="args">SQL 语句中使用的参数值，对应 SQL 语句中 @0 格式的参数。</param>
        /// <returns>一个用于遍历所有行数据的迭代器。</returns>
        public static IEnumerable<SqlDataReader> executeSqlRows(string sql, params object[] args) {
            var conn = createConnection();
            var cmd = new SqlCommand(sql, conn);
            addParameters(cmd, args);
            return new RowEnumerator(cmd.ExecuteReader(CommandBehavior.CloseConnection));
        }

        /// <summary>
        /// 执行数据库语句返回一个用于遍历所有行数据的迭代器。
        /// </summary>
        /// <param name="sql">要执行的 SQL 语句。</param>
        /// <returns>一个用于遍历所有行数据的迭代器。</returns>
        public static IEnumerable<SqlDataReader> executeSqlRows(string sql) {
            return executeSqlRows(sql, null);
        }

        private struct RowEnumerator : IEnumerator<SqlDataReader>, IEnumerable<SqlDataReader> {

            private readonly SqlDataReader _reader;

            public RowEnumerator(SqlDataReader reader) {
                _reader = reader;
            }

            /// <summary>
            /// 获取集合中位于枚举数当前位置的元素。
            /// </summary>
            /// <returns>
            /// 集合中位于枚举数当前位置的元素。
            /// </returns>
            public SqlDataReader Current {
                get {
                    return _reader;
                }
            }

            /// <summary>
            /// 执行与释放或重置非托管资源相关的应用程序定义的任务。
            /// </summary>
            /// <filterpriority>2</filterpriority>
            public void Dispose() {
                _reader.Dispose();
            }

            /// <summary>
            /// 获取集合中的当前元素。
            /// </summary>
            /// <returns>
            /// 集合中的当前元素。
            /// </returns>
            /// <filterpriority>2</filterpriority>
            object System.Collections.IEnumerator.Current {
                get {
                    return _reader;
                }
            }

            /// <summary>
            /// 将枚举数推进到集合的下一个元素。
            /// </summary>
            /// <returns>
            /// 如果枚举数成功地推进到下一个元素，则为 true；如果枚举数越过集合的结尾，则为 false。
            /// </returns>
            /// <exception cref="T:System.InvalidOperationException">在创建了枚举数后集合被修改了。</exception><filterpriority>2</filterpriority>
            public bool MoveNext() {
                return _reader.Read();
            }

            /// <summary>
            /// 将枚举数设置为其初始位置，该位置位于集合中第一个元素之前。
            /// </summary>
            /// <exception cref="T:System.InvalidOperationException">在创建了枚举数后集合被修改了。</exception><filterpriority>2</filterpriority>
            public void Reset() {
                throw new InvalidOperationException("无法重置 SqlDataReader，请重新查询");
            }

            /// <summary>
            /// 返回一个循环访问集合的枚举器。
            /// </summary>
            /// <returns>
            /// 可用于循环访问集合的 <see cref="T:System.Collections.Generic.IEnumerator`1"/>。
            /// </returns>
            /// <filterpriority>1</filterpriority>
            public IEnumerator<SqlDataReader> GetEnumerator() {
                return this;
            }

            /// <summary>
            /// 返回一个循环访问集合的枚举器。
            /// </summary>
            /// <returns>
            /// 可用于循环访问集合的 <see cref="T:System.Collections.IEnumerator"/> 对象。
            /// </returns>
            /// <filterpriority>2</filterpriority>
            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
                return this;
            }
        }

        /// <summary>
        /// 执行数据库语句返回一个内存表。
        /// </summary>
        /// <param name="sql">要执行的 SQL 语句。</param>
        /// <param name="args">SQL 语句中使用的参数值，对应 SQL 语句中 @0 格式的参数。</param>
        /// <returns>一个内存表。</returns>
        public static DataTable executeSqlTable(string sql, params object[] args) {
            using (var conn = createConnection()) {
                var cmd = new SqlCommand(sql, conn);
                addParameters(cmd, args);
                var result = new DataTable();
                result.Load(cmd.ExecuteReader());
                return result;
            }
        }

        /// <summary>
        /// 执行数据库语句返回一个内存表。
        /// </summary>
        /// <param name="sql">要执行的 SQL 语句。</param>
        /// <returns>一个内存表。</returns>
        public static DataTable executeSqlTable(string sql) {
            return executeSqlTable(sql, null);
        }

        /// <summary>
        /// 执行数据库语句返回一个表示第一行数据的内存数组。
        /// </summary>
        /// <param name="sql">要执行的 SQL 语句。</param>
        /// <param name="args">SQL 语句中使用的参数值，对应 SQL 语句中 @0 格式的参数。</param>
        /// <returns>一个内存数组。</returns>
        public static object[] executeSqlArray(string sql, params object[] args) {
            using (var conn = createConnection()) {
                var cmd = new SqlCommand(sql, conn);
                addParameters(cmd, args);
                var reader = cmd.ExecuteReader();
                if (!reader.Read()) {
                    return null;
                }
                var result = new object[reader.FieldCount];
                for (var i = 0; i < result.Length; i++) {
                    result[i] = reader[i];
                }
                return result;
            }
        }

        /// <summary>
        /// 执行数据库语句返回一个表示第一行数据的内存数组。
        /// </summary>
        /// <param name="sql">要执行的 SQL 语句。</param>
        /// <returns>一个内存数组。</returns>
        public static object[] executeSqlArray(string sql) {
            return executeSqlArray(sql, null);
        }

        private static void addParameters(SqlCommand cmd, object[] args) {
            if (args == null) {
                return;
            }
            for (int i = 0; i < args.Length; i++) {
                cmd.Parameters.AddWithValue(i.ToString(), args[i] ?? DBNull.Value);
            }
        }

        #endregion

        #region 底层执行存储过程操作

        /// <summary>
        /// 执行存储过程并返回受影响的行数。
        /// </summary>
        /// <param name="procedure">要执行的存储过程。</param>
        /// <param name="args">传递给存储过程的参数值。</param>
        /// <returns>受影响的行数。</returns>
        public static int executeProcedureNonQuery(string procedure, params SqlParameter[] args) {
            using (var conn = createConnection()) {
                return conn.createProcedure(procedure, args).ExecuteNonQuery();
            }
        }

        /// <summary>
        /// 执行存储过程并返回数据库返回值。
        /// </summary>
        /// <param name="procedure">要执行的存储过程。</param>
        /// <param name="returnDbtype">数据库返回值类型。</param>
        /// <param name="args">传递给存储过程的参数值。</param>
        /// <returns>返回数据库的返回值。</returns>
        public static object executeProcedureReturnValue(string procedure, SqlDbType returnDbtype, params SqlParameter[] args) {
            using (var conn = createConnection()) {
                return conn.createProcedure(procedure, args).executeReturnValue(returnDbtype);
            }
        }

        /// <summary>
        /// 执行存储过程并返回数据库返回值。
        /// </summary>
        /// <param name="procedure">要执行的存储过程。</param>
        /// <param name="args">传递给存储过程的参数值。</param>
        /// <returns>返回数据库的返回值。</returns>
        public static object executeProcedureReturnValue(string procedure, params SqlParameter[] args) {
            return executeProcedureReturnValue(procedure, SqlDbType.Int, args);
        }

        /// <summary>
        /// 执行存储过程并返回结果集中的第一行的第一列。忽略其它行或列。
        /// </summary>
        /// <param name="procedure">要执行的存储过程。</param>
        /// <param name="args">传递给存储过程的参数值。</param>
        /// <returns>结果集中第一行的第一列；如果结果集为空，则为 null。返回的最大字符数为 2033 个字符。</returns>
        public static object executeProcedureScalar(string procedure, params SqlParameter[] args) {
            using (var conn = createConnection()) {
                return conn.createProcedure(procedure, args).ExecuteScalar();
            }
        }

        /// <summary>
        /// 执行存储过程并返回一个数据读取器。
        /// </summary>
        /// <param name="procedure">要执行的存储过程。</param>
        /// <param name="args">传递给存储过程的参数值。</param>
        /// <returns>一个数据读取器。需要释放其资源以关闭连接。</returns>
        public static SqlDataReader executeProcedureReader(string procedure, params SqlParameter[] args) {
            var conn = createConnection();
            return conn.createProcedure(procedure, args).ExecuteReader(CommandBehavior.CloseConnection);
        }

        /// <summary>
        /// 执行存储过程返回一个用于遍历所有行数据的迭代器。
        /// </summary>
        /// <param name="procedure">要执行的存储过程。</param>
        /// <param name="args">传递给存储过程的参数值。</param>
        /// <returns>一个用于遍历所有行数据的迭代器。</returns>
        public static IEnumerable<SqlDataReader> executeProcedureRows(string procedure, params SqlParameter[] args) {
            return new RowEnumerator(executeProcedureReader(procedure, args));
        }

        /// <summary>
        /// 执行数据库语句返回一个内存表。
        /// </summary>
        /// <param name="procedure">要执行的存储过程。</param>
        /// <param name="args">传递给存储过程的参数值。</param>
        /// <returns>一个内存表。</returns>
        public static DataTable executeProcedureTable(string procedure, params SqlParameter[] args) {
            using (var conn = createConnection()) {
                var cmd = conn.createProcedure(procedure, args);
                var result = new DataTable();
                result.Load(cmd.ExecuteReader());
                return result;
            }
        }

        /// <summary>
        /// 执行存储过程返回一个表示第一行数据的内存数组。
        /// </summary>
        /// <param name="procedure">要执行的存储过程。</param>
        /// <param name="args">传递给存储过程的参数值。</param>
        /// <returns>一个内存数组。</returns>
        public static object[] executeProcedureArray(string procedure, params SqlParameter[] args) {
            using (var conn = createConnection()) {
                var cmd = conn.createProcedure(procedure, args);
                var reader = cmd.ExecuteReader();
                if (!reader.Read()) {
                    return null;
                }
                var result = new object[reader.FieldCount];
                for (var i = 0; i < result.Length; i++) {
                    result[i] = reader[i];
                }
                return result;
            }
        }

        #endregion

        #region SQL 生成和执行

        /// <summary>
        /// 执行一个简单的 INSERT 语句。
        /// </summary>
        /// <param name="table">要更新的表。</param>
        /// <param name="fields">要插入的字段。格式如“fieldA, fieldB”。</param>
        /// <param name="values">插入的值。格式如“1, '2'”，其值必须和字段一一对应。</param>
        /// <param name="args">SQL 语句中使用的参数值，对应 SQL 语句中 @0 格式的参数。</param>
        /// <returns>返回受影响的条数。</returns>
        public static int insert(string table, string fields, string values, params object[] args) {
            StringBuilder sb = new StringBuilder(32);
            sb.Append("INSERT INTO");
            sb.Append(table);
            sb.Append("(");
            sb.Append(fields);
            sb.Append(")");
            sb.Append(" VALUES(");
            sb.Append(values);
            sb.Append(")");
            return executeSqlNonQuery(sb.ToString(), args);
        }

        /// <summary>
        /// 执行一个简单的 DELETE 语句。
        /// </summary>
        /// <param name="table">要更新的表。</param>
        /// <param name="where">删除的条件表达式。如果无条件请传递 “1=1”。</param>
        /// <param name="args">SQL 语句中使用的参数值，对应 SQL 语句中 @0 格式的参数。</param>
        /// <returns>返回受影响的条数。</returns>
        public static int delete(string table, string where, params object[] args) {
            StringBuilder sb = new StringBuilder(32);
            sb.Append("DELETE FROM ");
            sb.Append(table);
            sb.Append(" WHERE ");
            sb.Append(where);
            return executeSqlNonQuery(sb.ToString(), args);
        }

        /// <summary>
        /// 执行一个简单的 UPDATE 语句。
        /// </summary>
        /// <param name="table">要更新的表。</param>
        /// <param name="values">要更新的字段值。格式如“fieldA='1', fieldB='2'”</param>
        /// <param name="where">更新的条件表达式。如果无条件请传递 “1=1”。</param>
        /// <param name="args">SQL 语句中使用的参数值，对应 SQL 语句中 @0 格式的参数。</param>
        /// <returns>返回受影响的条数。</returns>
        public static int update(string table, string values, string where, params object[] args) {
            StringBuilder sb = new StringBuilder(32);
            sb.Append("UPDATE ");
            sb.Append(table);
            sb.Append(" SET ");
            sb.Append(values);
            sb.Append(" WHERE ");
            sb.Append(where);
            return executeSqlNonQuery(sb.ToString(), args);
        }

        /// <summary>
        /// 执行一个简单的 SELECT 语句并返回多行数据。
        /// </summary>
        /// <param name="table">要查询的表。</param>
        /// <param name="fields">要查询的字段。格式如“fieldA, fieldB”。要查询所有字段请传递“*”。</param>
        /// <param name="where">查询的条件表达式。如果无条件请传递 null。</param>
        /// <param name="orderBy">排序使用的字段。如果不排序请传递 null。如果需要倒序，在字段名后追加“DESC”。</param>
        /// <param name="args">SQL 语句中使用的参数值，对应 SQL 语句中 @0 格式的参数。</param>
        /// <returns>一个用于遍历所有行数据的迭代器。</returns>
        public static IEnumerable<SqlDataReader> selectRows(string table, string fields = "*", string where = null, string orderBy = null, params object[] args) {
            return executeSqlRows(generateSelect(table, fields, where, orderBy), args);
        }

        /// <summary>
        /// 执行一个简单的 SELECT 语句并返回多行数据。
        /// </summary>
        /// <param name="table">要查询的表。</param>
        /// <param name="fields">要查询的字段。格式如“fieldA, fieldB”。要查询所有字段请传递“*”。</param>
        /// <param name="where">查询的条件表达式。如果无条件请传递 null。</param>
        /// <param name="orderBy">排序使用的字段。如果不排序请传递 null。如果需要倒序，在字段名后追加“DESC”。</param>
        /// <returns>一个用于遍历所有行数据的迭代器。</returns>
        public static IEnumerable<SqlDataReader> selectRows(string table, string fields = "*", string where = null, string orderBy = null) {
            return executeSqlRows(generateSelect(table, fields, where, orderBy));
        }

        /// <summary>
        /// 执行一个简单的 SELECT 语句并返回内存数据表。
        /// </summary>
        /// <param name="table">要查询的表。</param>
        /// <param name="fields">要查询的字段。格式如“fieldA, fieldB”。要查询所有字段请传递“*”。</param>
        /// <param name="where">查询的条件表达式。如果无条件请传递 null。</param>
        /// <param name="orderBy">排序使用的字段。如果不排序请传递 null。如果需要倒序，在字段名后追加“DESC”。</param>
        /// <param name="args">SQL 语句中使用的参数值，对应 SQL 语句中 @0 格式的参数。</param>
        /// <returns>一个用于遍历所有行数据的迭代器。</returns>
        public static DataTable selectTable(string table, string fields = "*", string where = null, string orderBy = null, params object[] args) {
            return executeSqlTable(generateSelect(table, fields, where, orderBy), args);
        }

        /// <summary>
        /// 执行一个简单的 SELECT 语句并返回内存数据表。
        /// </summary>
        /// <param name="table">要查询的表。</param>
        /// <param name="fields">要查询的字段。格式如“fieldA, fieldB”。要查询所有字段请传递“*”。</param>
        /// <param name="where">查询的条件表达式。如果无条件请传递 null。</param>
        /// <param name="orderBy">排序使用的字段。如果不排序请传递 null。如果需要倒序，在字段名后追加“DESC”。</param>
        /// <returns>一个用于遍历所有行数据的迭代器。</returns>
        public static DataTable selectTable(string table, string fields = "*", string where = null, string orderBy = null) {
            return executeSqlTable(generateSelect(table, fields, where, orderBy));
        }

        /// <summary>
        /// 执行一个简单的 SELECT 语句并返回数据读取器。
        /// </summary>
        /// <param name="table">要查询的表。</param>
        /// <param name="fields">要查询的字段。格式如“fieldA, fieldB”。要查询所有字段请传递“*”。</param>
        /// <param name="where">查询的条件表达式。如果无条件请传递 null。</param>
        /// <param name="orderBy">排序使用的字段。如果不排序请传递 null。如果需要倒序，在字段名后追加“DESC”。</param>
        /// <param name="args">SQL 语句中使用的参数值，对应 SQL 语句中 @0 格式的参数。</param>
        /// <returns>一个用于遍历所有行数据的迭代器。</returns>
        public static SqlDataReader selectReader(string table, string fields = "*", string where = null, string orderBy = null, params object[] args) {
            return executeSqlReader(generateSelect(table, fields, where, orderBy), args);
        }

        /// <summary>
        /// 执行一个简单的 SELECT 语句并返回数据读取器。
        /// </summary>
        /// <param name="table">要查询的表。</param>
        /// <param name="fields">要查询的字段。格式如“fieldA, fieldB”。要查询所有字段请传递“*”。</param>
        /// <param name="where">查询的条件表达式。如果无条件请传递 null。</param>
        /// <param name="orderBy">排序使用的字段。如果不排序请传递 null。如果需要倒序，在字段名后追加“DESC”。</param>
        /// <returns>一个用于遍历所有行数据的迭代器。</returns>
        public static SqlDataReader selectReader(string table, string fields = "*", string where = null, string orderBy = null) {
            return executeSqlReader(generateSelect(table, fields, where, orderBy));
        }

        private static string generateSelect(string table, string fields, string where, string orderBy) {
            StringBuilder sb = new StringBuilder(32);
            sb.Append("SELECT ");
            sb.Append(fields);
            sb.Append(" FROM ");
            sb.Append(table);
            if (where != null) {
                sb.Append(" WHERE ");
                sb.Append(where);
            }
            if (orderBy != null) {
                sb.Append(" ORDER BY ");
                sb.Append(orderBy);
            }
            return sb.ToString();
        }

        /// <summary>
        /// 执行一个简单的 SELECT 语句。
        /// </summary>
        /// <param name="table">要查询的表。</param>
        /// <param name="pageNumber">当前页码。页码从 0 开始。</param>
        /// <param name="pageSize">每页显示的条数。</param>
        /// <param name="fields">要查询的字段。格式如“fieldA, fieldB”。要查询所有字段请传递“*”。</param>
        /// <param name="where">查询的条件表达式。如果无条件请传递 null。</param>
        /// <param name="orderBy">排序使用的字段。如果不排序请传递 null。如果需要倒序，在字段名后追加“DESC”。</param>
        /// <param name="args">SQL 语句中使用的参数值，对应 SQL 语句中 @0 格式的参数。</param>
        /// <returns>一个用于遍历所有行数据的迭代器。</returns>
        public static IEnumerable<SqlDataReader> selectRows(string table, int pageNumber, int pageSize = 20, string fields = "*", string where = null, string orderBy = "1", params object[] args) {
            return executeSqlRows(generateSelect(table, pageNumber, pageSize, fields, where, orderBy), args);
        }

        /// <summary>
        /// 查询指定表。
        /// </summary>
        /// <param name="table">要查询的表。</param>
        /// <param name="pageNumber">当前页码。页码从 1 开始。</param>
        /// <param name="pageSize">每页显示的条数。</param>
        /// <param name="fields">要查询的字段。格式如“fieldA, fieldB”。要查询所有字段请传递“*”。</param>
        /// <param name="where">查询的条件表达式。如果无条件请传递 null。</param>
        /// <param name="orderBy">排序使用的字段。如果不排序请传递 null。如果需要倒序，在字段名后追加“DESC”。</param>
        /// <param name="args">SQL 语句中使用的参数值，对应 SQL 语句中 @0 格式的参数。</param>
        /// <returns>一个用于遍历所有行数据的迭代器。</returns>
        public static DataTable selectTable(string table, int pageNumber, int pageSize = 20, string fields = "*", string where = null, string orderBy = "1", params object[] args) {
            return executeSqlTable(generateSelect(table, pageNumber, pageSize, fields, where, orderBy), args);
        }

        /// <summary>
        /// 查询指定表。
        /// </summary>
        /// <param name="table">要查询的表。</param>
        /// <param name="pageNumber">当前页码。页码从 1 开始。</param>
        /// <param name="pageSize">每页显示的条数。</param>
        /// <param name="fields">要查询的字段。格式如“fieldA, fieldB”。要查询所有字段请传递“*”。</param>
        /// <param name="where">查询的条件表达式。如果无条件请传递 null。</param>
        /// <param name="orderBy">排序使用的字段。如果不排序请传递 null。如果需要倒序，在字段名后追加“DESC”。</param>
        /// <param name="args">SQL 语句中使用的参数值，对应 SQL 语句中 @0 格式的参数。</param>
        /// <returns>一个用于遍历所有行数据的迭代器。</returns>
        public static SqlDataReader selectReader(string table, int pageNumber, int pageSize = 20, string fields = "*", string where = null, string orderBy = "1", params object[] args) {
            return executeSqlReader(generateSelect(table, pageNumber, pageSize, fields, where, orderBy), args);
        }

        private static string generateSelect(string table, int pageNumber, int pageSize, string fields, string where, string orderBy) {

            // 将 pageNumber 更新为条数。
            pageNumber--;
            pageNumber *= pageSize;
            pageNumber++;
            return String.Format("SELECT * FROM( SELECT {0}, ROW_NUMBER() OVER (ORDER BY {2}) AS _rowNumber_ FROM {1}{5}) sub WHERE _rowNumber_ >= {3} AND _rowNumber_ < {4}", fields, table, orderBy, pageNumber, pageNumber + pageSize, where != null ? " WHERE " + where : null);
        }

        /// <summary>
        /// 统计指定表的行数。
        /// </summary>
        /// <param name="table">要查询的表。</param>
        /// <param name="where">查询的条件表达式。如果无条件请传递 null。</param>
        /// <param name="args">SQL 语句中使用的参数值，对应 SQL 语句中 @0 格式的参数。</param>
        /// <returns>返回行数。</returns>
        public static int count(string table, string where = null, params object[] args) {
            StringBuilder sb = new StringBuilder(32);
            sb.Append("SELECT COUNT(0) FROM ");
            sb.Append(table);
            if (where != null) {
                sb.Append(" WHERE ");
                sb.Append(where);
            }
            return (int)executeSqlScalar(sb.ToString(), args);
        }

        #endregion

        #region SqlDataReaderExtensions 扩展

        /// <summary>
        /// 获取指定列的字符串形式的值。
        /// </summary>
        /// <param name="reader">要读取的读取器。</param>
        /// <param name="fieldName">列的名称。</param>
        /// <returns>指定列的值。</returns>
        /// <exception cref="T:System.InvalidCastException">指定的强制转换无效。</exception>
        public static string getString(this SqlDataReader reader, string fieldName) {
            var i = reader.GetOrdinal(fieldName);
            return reader.IsDBNull(i) ? null : reader.GetString(i);
        }

        /// <summary>
        /// 获取指定列的 <see cref="T:System.DateTime"/> 对象形式的值。
        /// </summary>
        /// <param name="reader">要读取的读取器。</param>
        /// <param name="fieldName">列的名称。</param>
        /// <returns>指定列的值。</returns>
        /// <exception cref="T:System.InvalidCastException">指定的强制转换无效。</exception>
        public static DateTime getDateTime(this SqlDataReader reader, string fieldName) {
            var i = reader.GetOrdinal(fieldName);
            return reader.IsDBNull(i) ? DateTime.MinValue : reader.GetDateTime(i);
        }

        /// <summary>
        /// 获取指定列的字节形式的值。
        /// </summary>
        /// <param name="reader">要读取的读取器。</param>
        /// <param name="fieldName">列的名称。</param>
        /// <returns>指定列的值。</returns>
        /// <exception cref="T:System.InvalidCastException">指定的强制转换无效。</exception>
        public static byte getByte(this SqlDataReader reader, string fieldName) {
            return reader.GetByte(reader.GetOrdinal(fieldName));
        }

        /// <summary>
        /// 获取指定列的 16 位有符号整数形式的值。
        /// </summary>
        /// <param name="reader">要读取的读取器。</param>
        /// <param name="fieldName">列的名称。</param>
        /// <returns>指定列的值。</returns>
        /// <exception cref="T:System.InvalidCastException">指定的强制转换无效。</exception>
        public static short getShort(this SqlDataReader reader, string fieldName) {
            return reader.GetInt16(reader.GetOrdinal(fieldName));
        }

        /// <summary>
        /// 获取指定列的 32 位有符号整数形式的值。
        /// </summary>
        /// <param name="reader">要读取的读取器。</param>
        /// <param name="fieldName">列的名称。</param>
        /// <returns>指定列的值。</returns>
        /// <exception cref="T:System.InvalidCastException">指定的强制转换无效。</exception>
        public static int getInt(this SqlDataReader reader, string fieldName) {
            return reader.GetInt32(reader.GetOrdinal(fieldName));
        }

        /// <summary>
        /// 获取指定列的 64 位有符号整数形式的值。
        /// </summary>
        /// <param name="reader">要读取的读取器。</param>
        /// <param name="fieldName">列的名称。</param>
        /// <returns>指定列的值。</returns>
        /// <exception cref="T:System.InvalidCastException">指定的强制转换无效。</exception>
        public static long getLong(this SqlDataReader reader, string fieldName) {
            return reader.GetInt64(reader.GetOrdinal(fieldName));
        }

        /// <summary>
        /// 获取第一列的 64 位有符号整数形式的值。
        /// </summary>
        /// <param name="reader">要读取的读取器。</param>
        /// <returns>指定列的值。</returns>
        /// <exception cref="T:System.InvalidCastException">指定的强制转换无效。</exception>
        public static long getId(this SqlDataReader reader) {
            return reader.GetInt64(0);
        }

        /// <summary>
        /// 获取一个值，该值指示列中是否包含不存在的或缺少的值。
        /// </summary>
        /// <param name="reader">要读取的读取器。</param>
        /// <param name="fieldName">列的名称。</param>
        /// <returns>指定列的值。</returns>
        /// <exception cref="T:System.InvalidCastException">指定的强制转换无效。</exception>
        public static bool isDBNull(this SqlDataReader reader, string fieldName) {
            return reader.IsDBNull(reader.GetOrdinal(fieldName));
        }

        #endregion

    }

}